#include "database_service.h"
#include "network_service.h"
#include "StringUtil.h"
#include "GameUtil.h"
DatabaseService::DatabaseService(void)
{
}

DatabaseService::~DatabaseService(void)
{
}

void DatabaseService::onStart( void* startArgs )
{
	m_networkService = (NetworkService*)startArgs;
	m_conn = mysql_init(NULL);
	//m_conn = mysql_real_connect(m_conn, "127.0.0.1", "root", "zheng188", "playerinfo", 3306, NULL, 0);
	m_conn = mysql_real_connect(m_conn, "120.26.201.243", "root", "zhengcy", "playerinfo", 3306, NULL, 0);
	m_proto = db_protoCreateProto();
}

void DatabaseService::onMsg( JService* service, int msgId, int sessionId, void* args )
{
	if(msgId == kDBMsgPlayerInfoRequest) {
		DBMsgPlayerInfoRequest* req = (DBMsgPlayerInfoRequest*)args;
		this->procGetPlayerInfoRequest(sessionId, req);
		delete req;
	}
	else if (msgId == kDBMsgAddRegisterPlayerRequest) {
		DBMsgAddRegisterPlayerRequest* req = (DBMsgAddRegisterPlayerRequest*)args;
		this->procAddRegisterPlayerRequest(sessionId, req);
		delete req;
	}
	else if (msgId == kDBMsgActivatePlayerRequest) {
		DBMsgActivatePlayerRequest* req = (DBMsgActivatePlayerRequest*)args;
		this->procActivatePlayerRequest(sessionId, req);
		delete req;
	}
	else if (msgId == kDBMsgSavePlayerInfo) {
		DBMsgSavePlayerInfo* req = (DBMsgSavePlayerInfo*)args;
		this->procSavePlayerInfo(sessionId, req);
		delete req;	
	}
}

void DatabaseService::procGetPlayerInfoRequest( int sessionId, DBMsgPlayerInfoRequest* req )
{
	if (!m_conn) {
		return;
	}
	DBMsgPlayerInfoResponse resp;
	const char* sql = "call login(?, ?, ?, @exist, @phoneNoOutput, @nickName, @lastLoginTime, @score);";
	MYSQL_STMT* stmt = createStmt(sql);
	MYSQL_BIND bindInputs[3] = {};
	MYSQL_BIND bindOutputs[5] = {};

	this->bindString(&bindInputs[0], req->userName.c_str());
	this->bindString(&bindInputs[1], req->password.c_str());
	this->bindBool(&bindInputs[2], req->isGuest);

	bool exist = false;
	bindOutputs[0].buffer = &exist;
	bindOutputs[0].buffer_type = MYSQL_TYPE_TINY;
	bindOutputs[0].buffer_length = 1;

	char phoneNo[512] = {};
	bindOutputs[1].buffer = phoneNo;
	bindOutputs[1].buffer_type = MYSQL_TYPE_STRING;
	bindOutputs[1].buffer_length = sizeof(phoneNo);

	char nickName[512] = {};
	bindOutputs[2].buffer = nickName;
	bindOutputs[2].buffer_type = MYSQL_TYPE_STRING;
	bindOutputs[2].buffer_length = sizeof(nickName);

	char lastLoginTime[512] = {};
	bindOutputs[3].buffer = lastLoginTime;
	bindOutputs[3].buffer_type = MYSQL_TYPE_STRING;
	bindOutputs[3].buffer_length = sizeof(lastLoginTime);

	int score = 0;
	bindOutputs[4].buffer = &score;
	bindOutputs[4].buffer_type = MYSQL_TYPE_LONG;
	bindOutputs[4].buffer_length = sizeof(score);

	auto ret = mysql_stmt_prepare(stmt, sql, strlen(sql));
	ret = mysql_stmt_bind_param(stmt, bindInputs);
	

	ret = mysql_stmt_execute(stmt);
	mysql_stmt_close(stmt);
	if (ret != 0) {
		printf("error:%s\n", stmt->last_error);
		
	}

	else {
		sql = "select @exist, @phoneNoOutput, @nickName, @lastLoginTime, @score; ";
		stmt = createStmt(sql);
		mysql_stmt_prepare(stmt, sql, strlen(sql));
		ret = mysql_stmt_bind_result(stmt, bindOutputs);
		ret = mysql_stmt_execute(stmt);
		ret = mysql_stmt_store_result(stmt);

		while (!mysql_stmt_fetch(stmt))  {
			break;
		}
		mysql_stmt_close(stmt);
	}

	resp.userName = req->userName;
	if (exist) {
		resp.isSuccess = true;
		DBMSGPlayerInfo& playerInfo = resp.playerInfo;
		playerInfo.userName = req->userName;
		playerInfo.isGuest = req->isGuest;
		playerInfo.nickName = nickName;
		playerInfo.lastLoginTime = lastLoginTime;
		playerInfo.phoneNo = phoneNo;
		playerInfo.score = score;
	}

	JMsgWriter writer;
	resp.encode(m_proto, &writer);
	m_networkService->sendConnectionData(sessionId, writer.getBuffer(), writer.getBufferLen());	
}

void DatabaseService::procAddRegisterPlayerRequest(int sessionId, DBMsgAddRegisterPlayerRequest * req)
{
	if (!m_conn) {
		return;
	}
	DBMsgAddRegisterPlayerResponse resp;
	resp.userName = req->userName;
	const char* sql = "insert into playerinfo(userName, passwordMd5, isGuest) "
		"values(?, ?, ?)";

	MYSQL_STMT* stmt = createStmt(sql);
	MYSQL_BIND binds[6] = {};

	int ret = mysql_stmt_prepare(stmt, sql, strlen(sql));

	bindString(&binds[0], req->userName.c_str());
	
	bindString(&binds[1], req->passwordSha1.c_str());
	
	bindBool(&binds[2], false);	

	auto bindRet = mysql_stmt_bind_param(stmt, binds);
	
	ret = mysql_stmt_execute(stmt);
	if (ret != 0) {
		resp.isSuccess = false;
		printf("error:%s\n", stmt->last_error);
	}
	else {
		resp.isSuccess = true;
	}
	
	JMsgWriter writer;
	resp.encode(m_proto, &writer);
	m_networkService->sendConnectionData(sessionId, writer.getBuffer(), writer.getBufferLen());	
	mysql_stmt_close(stmt);
}

void DatabaseService::procActivatePlayerRequest(int sessionId, DBMsgActivatePlayerRequest * req)
{
	DBMsgActivatePlayerResponse resp;
	resp.guestUserName = req->guestUserName;
	resp.newUserName = req->newUserName;

	auto stmt = createStmt("");
	
	const char* sql = "select activateUser(?, ?, ?, ?)";
	MYSQL_BIND binds[4] = {};
	MYSQL_BIND bindRet = {};
	bindString(&binds[0], req->guestUserName.c_str());
	bindString(&binds[1], req->newUserName.c_str());
	bindString(&binds[2], req->newPassword.c_str());
	bindString(&binds[3], req->phoneNo.c_str());
	int ret = 0;
	bindRet.buffer = &ret;
	bindRet.buffer_length = sizeof(ret);
	bindRet.buffer_type = MYSQL_TYPE_LONG;

	auto execRet = mysql_stmt_prepare(stmt, sql, strlen(sql));

	if (execRet != 0) {
		resp.errorCode = -1;
		goto out;
	}
	execRet = mysql_stmt_bind_param(stmt, binds);
	if (execRet != 0) {
		resp.errorCode = -1;
		goto out;
	}

	execRet = mysql_stmt_bind_result(stmt, &bindRet);
	if (execRet != 0) {
		resp.errorCode = -1;
		goto out;
	}

	execRet = mysql_stmt_execute(stmt);

	if (execRet != 0) {
		resp.errorCode = -2;
		goto out;
	}

	execRet = mysql_stmt_store_result(stmt);
	if (execRet != 0) {
		resp.errorCode = -3;
		goto out;
	}

	while (mysql_stmt_fetch(stmt) == 0) {		
		break;
	}

	if (ret != 1) {
		resp.errorCode = -3;
		goto out;
	}

	resp.isSuccess = true;

out:
	JMsgWriter writer;
	resp.encode(m_proto, &writer);
	m_networkService->sendConnectionData(sessionId, writer.getBuffer(), writer.getBufferLen());
	mysql_stmt_close(stmt);
}

void DatabaseService::procSavePlayerInfo(int sessionId, DBMsgSavePlayerInfo * req)
{
	auto stmt = createStmt("");
	int paramIndex = 0;
	if (req->playerInfo.nickName == "" && req->playerInfo.phoneNo == "") {
		return;
	}

	MYSQL_BIND binds[3] = {};
	string sql = "update playerinfo set ";
	string params;
	if (req->playerInfo.nickName != "") {
		params.append("nickName = ?");
		bindString(&binds[paramIndex++], req->playerInfo.nickName.c_str());
	}

	if (req->playerInfo.phoneNo != "") {
		if (!params.empty()) {
			params.append(",");
			bindString(&binds[paramIndex++], req->playerInfo.phoneNo.c_str());
		}
		else {
			params.append("set ");
			bindString(&binds[paramIndex++], req->playerInfo.phoneNo.c_str());
		}
		params.append("phoneNo = ?");
	}
	sql.append(params);
	sql.append(" where userName = ?");
	sql.append(";");
	bindString(&binds[paramIndex++], req->playerInfo.userName.c_str());
	mysql_stmt_prepare(stmt, sql.c_str(), sql.size());
	mysql_stmt_bind_param(stmt, binds);
	mysql_stmt_execute(stmt);
	mysql_stmt_close(stmt);
}

MYSQL_STMT * DatabaseService::createStmt(const std::string & sql)
{
	MYSQL_STMT* stmt = mysql_stmt_init(m_conn);	
	return stmt;
}

void DatabaseService::bindString(MYSQL_BIND * bind, const char * str)
{
	bind->buffer = (void*)str;
	bind->buffer_type = MYSQL_TYPE_STRING;
	bind->buffer_length = strlen(str);
}

void DatabaseService::bindBool(MYSQL_BIND* bind, const bool & value)
{
	bind->buffer = (void*)&value;
	bind->buffer_type = MYSQL_TYPE_TINY;
	bind->buffer_length = 1;
}
